package com.lyn.xupdate;

import android.app.Application;
import android.content.pm.PackageInfo;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.lyn.xupdate.entity.UpdateEntity;
import com.lyn.xupdate.interfaces.CheckUpdateListener;
import com.lyn.xupdate.interfaces.DownloadListener;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;

/**
 * XUpdate
 * @author longyn 2024/02/19
 * @version 1.0.0
 */
public class XUpdate {

    public static final String TAG = "XUpdate";

    private static final class XUpdateTypeClass {
        private static final XUpdate in = new XUpdate();
    }

    public static XUpdate getInstance() {
        return XUpdateTypeClass.in;
    }

    private Application application;
    private PackageInfo packageInfo;

    private String checkUpdateHostUrl;
    private int versionCode;

    private String versionName;

    private String appId;

    private String packageName;

    private final OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
    private final MediaType mediaType = MediaType.parse("application/json,charset=utf-8");

    private final ExecutorService executor = Executors.newSingleThreadExecutor();

    private final Handler handler = new Handler(Looper.getMainLooper());

    public XUpdate setCheckUpdateHostUrl(String checkUpdateHostUrl) {
        this.checkUpdateHostUrl = checkUpdateHostUrl;
        return this;
    }


    public XUpdate setAppId(String appId) {
        this.appId = appId;
        return this;
    }

    public void create(Application application) {
        this.application = application;
        this.packageName = application.getPackageName();
        try {
            packageInfo = this.application.getPackageManager().getPackageInfo(application.getPackageName(), 0);
            versionCode = packageInfo.versionCode;
            versionName = packageInfo.versionName;
        } catch (Throwable e) {
            e.printStackTrace();
        }
        if (TextUtils.isEmpty(checkUpdateHostUrl)) {
            throw new NullPointerException("必须调用setCheckUpdateHostUrl");
        }
        if (TextUtils.isEmpty(appId)) {
            throw new NullPointerException("必须调用setAppId");
        }
    }

    public void checkUpdate(@NonNull final CheckUpdateListener checkUpdateListener) {
        executor.execute(() -> {
            try {
                handler.post(checkUpdateListener::onCheckUpdateStart);
                JSONObject data = new JSONObject();
                data.put("appId", appId);
                data.put("versionCode", versionCode);
                data.put("versionName", versionName);
                data.put("packageName", packageName);
                RequestBody requestBody = RequestBody.create(mediaType, data.toJSONString());
                Request request = new Request.Builder()
                        .url(checkUpdateHostUrl)
                        .post(requestBody)
                        .build();
                Response response = okHttpClient.newCall(request).execute();
                String result = null;
                if (response.body() != null) {
                    result = response.body().string();
                }
                if (TextUtils.isEmpty(result)){
                    return;
                }
                JSONObject jsonObject = JSONObject.parseObject(result);
                if (jsonObject.getIntValue("code") == 1){
                    JSONArray desc = jsonObject.getJSONArray("desc");
                    String downloadUrl = jsonObject.getString("downloadUrl");
                    String msg = jsonObject.getString("msg");
                    UpdateEntity updateEntity = new UpdateEntity();
                    updateEntity.setDesc(desc.toJavaList(String.class));
                    updateEntity.setMsg(msg);
                    updateEntity.setDownloadUrl(downloadUrl);
                    handler.post(() -> checkUpdateListener.onCheckUpdateSuccess(updateEntity));
                }else {
                    handler.post(() -> checkUpdateListener.onCheckUpdateError(jsonObject.getString("msg")));
                }
            }catch (Throwable e){
                e.printStackTrace();
                handler.post(() -> checkUpdateListener.onCheckUpdateError(e.getMessage()));
            }finally {
                handler.post(checkUpdateListener::onCheckUpdateEnd);
            }
        });
    }


    public void download(@NonNull final String url, @NonNull final DownloadListener downloadListener) {
        executor.execute(() -> {
            try {
                handler.post(downloadListener::onDownloadStart);
                Request request = new Request.Builder().url(url).build();
                Response response = okHttpClient.newCall(request).execute();
                if (response.code() == 200) {
                    ResponseBody body = response.body();
                    if (body != null) {
                        long contentLength = body.contentLength();
                        InputStream inputStream = body.byteStream();
                        File tempFile = File.createTempFile("update", ".apk");
                        FileOutputStream outputStream = new FileOutputStream(tempFile);
                        BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
                        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
                        byte[] readData = new byte[1024];
                        int readLength;
                        long count = 0;
                        while ((readLength = bufferedInputStream.read(readData)) > 0) {
                            count += readLength;
                            int progress = (int) (count * 1f / contentLength * 100);
                            handler.post(() -> downloadListener.onDownloadProgress(progress));
                            bufferedOutputStream.write(readData, 0, readLength);
                        }
                        bufferedInputStream.close();
                        bufferedOutputStream.close();
                        String absolutePath = tempFile.getAbsolutePath();
                        handler.post(() -> downloadListener.onDownloadSuccess(absolutePath));
                    }
                }
            } catch (Throwable e) {
                e.printStackTrace();
                handler.post(() -> downloadListener.onDownloadError(e.getMessage()));
            } finally {
                handler.post(downloadListener::onDownloadEnd);
            }
        });
    }
}
